#include "client.hpp"

using namespace std;

/*
	Client
*/

int main(int argc, char **argv)
{
	// Gestion des erreurs
	string err1 = "Echec : Pas assez ou trop d'arguments ";
	string err2 = "Echec : Creation du client impossible ";
	string err3 = "Echec : Connexion impossible ";
	string err4 = "Echec : Creation des threads impossible ";
	
	if (argc != 3)
	{
		cout << err1 << endl;
		usage(stdout);
		return 0;
	}
	
	// Recuperation des arguments
	char* hote = argv[1];
	unsigned short port = (short)(atoi(argv[2]));
	
	// Variables client
	Sock socketClient(SOCK_STREAM, 0);
	int descripteurClient;
	
	// Creation du client
	if (socketClient.good())
	{
		descripteurClient = socketClient.getsDesc();
	}
	else
	{	
		perror(err2.c_str());
		return 0;
	}
	
	// Designer le serveur
	SockDist socketDistante(hote, port);
	struct sockaddr_in* socketCV = socketDistante.getAdrDist();
	int longueurSocketCV = sizeof(struct sockaddr_in);
	
	// Demande de connexion au serveur
	int r = connect(descripteurClient, (struct sockaddr*)socketCV, longueurSocketCV);
	if (r < 0)
	{
		perror(err3.c_str());
		return 0;
	}
	
	// On passe la main aux deux threads
	cout << "Connexion reussie" << endl;
	
	pthread_t tAffichage; // Reception et affichages
	pthread_t tCommandes; // Ecoute du clavier et envois
	
	if(pthread_create(&tAffichage, NULL, threadAffichage, &descripteurClient) != 0)
	{
		perror(err4.c_str());
		return 0;	
	}
	
	if(pthread_create(&tCommandes, NULL, threadCommandes, &descripteurClient) != 0)
	{
		perror(err4.c_str());
		return 0;	
	}
	pthread_join(tCommandes, NULL);	
	
	// Fermeture de la socket
	close(descripteurClient);
	
	return 0;
}

void afficherGrille(char grille[17])
{
	system("clear");
	cout << "Vous visualisez seulement." << endl;
	formateGrille(grille);
}

// Quand le client a le controle
void afficherGrilleControle(char grille[17])
{
	system("clear");
	cout << "Vous avez le controle de la grille." << endl;
	cout << "h : haut, b : bas, d : droite, g : gauche." << endl;
	formateGrille(grille);
}

// Quand le client est en attente du controle
void afficherGrilleAttente(char grille[17])
{
	system("clear");
	cout << "Vous etes en attente du controle de la grille." << endl;
	formateGrille(grille);
}

void formateGrille(char grille[17])
{
	cout << "Grille : " << endl;
	cout << grille[0] << grille[1] << grille[2] << grille[3] << endl;
	cout << grille[4] << grille[5] << grille[6] << grille[7] << endl;
	cout << grille[8] << grille[9] << grille[10] << grille[11] << endl;
	cout << grille[12] << grille[13] << grille[14] << grille[15] << endl;
}

// Affiche le manuel
void usage(FILE *stream)
{
 	fprintf(stream, "Usage : \n");
	fprintf(stream, "client [hote] [port]\n");
}

// Recoit et affiche les grilles envoyees par le serveur
void* threadAffichage(void *arg)
{
	int *descripteur = (int*)arg;
	while(1)
	{
		char buffer[18];
		
		// Reception des donnees
		int rb = recv(*descripteur, &buffer, sizeof(buffer), 0);
		
		// Erreur de reception
		if(rb == -1)
		{
			cout << "Erreur lors de la reception" << endl;
			close(*descripteur);
			exit(0);
		}
		
		// Arret du serveur
		if(rb == 0)
		{
			cout << "Erreur : arret du serveur" << endl;
			close(*descripteur);
			exit(0);
		}
			
		// Si la reception s'est bien passee
		// Si le client a le controle
		if(buffer[16] == 'c')
			afficherGrilleControle(buffer);
		else
		{
			// Si le client est en attente
			if(buffer[16] == 'a')
				afficherGrilleAttente(buffer);
			else
				afficherGrille(buffer);
		}
	}
}

// Ecoute les commandes entrees par le client et les envoie au serveur
void* threadCommandes(void *arg)
{
	int *descripteur = (int*)arg;
	while(1)
	{
		// Pour les commandes entrees par le client
		char bufferClavier[3];
		
		fgets(bufferClavier, sizeof(bufferClavier), stdin);
		
		// La touche 'q' permets de se deconnecter
		if(bufferClavier[0] == 'q')
		{
			cout << "Arret du client" << endl;
			char q = 'q';
			int s = send(*descripteur, &q, sizeof(char), 0);
			if (s < 0)
				perror("Echec : Envoi impossible ");
			close(*descripteur);
			return NULL;
		}
		
		// Commande 'p' ou 'P' : demande de prise de controle du curseur
		if(bufferClavier[0] == 'p' || bufferClavier[0] == 'P')
		{
			cout << "Demande de prise de controle" << endl;
			char p = 'p';
			int s = send(*descripteur, &p, sizeof(char), 0);
			if(s < 0)
			{
				perror("Echec : envoi impossible ");
				close(*descripteur);
				return NULL;
			}
		}
		
		/* Commandes pour diriger la grille quand on a le controle:
		   haut : 'h', bas : 'b', gauche : 'g', droite : 'd'
		*/
		
		if (bufferClavier[0] == 'h' || bufferClavier[0] == 'b' ||
		    bufferClavier[0] == 'g' || bufferClavier[0] == 'd')
		{
			char cmd;
			cmd = bufferClavier[0];
			int s; // Nombre d'octets envoyes
			s = send(*descripteur, &cmd, sizeof(char), 0);
			if(s < 0)
			{
				perror("Echec : envoi impossible ");
				close(*descripteur);
				return NULL;
			}
		}
	}
}


